package club.yunqiang.club.templatedownload.service.impl;

import club.yunqiang.club.templatedownload.domain.dto.DropDownDataFillDTO;
import club.yunqiang.club.templatedownload.domain.enums.TemplateEnum;
import club.yunqiang.club.templatedownload.service.IDataFillService;
import club.yunqiang.club.templatedownload.service.IDictService;
import club.yunqiang.club.templatedownload.service.ITemplateService;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.WorkbookUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.CellReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

@Service
@Slf4j
public class TemplateServiceImpl implements ITemplateService {

    @Autowired
    private IDictService dictService;

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void download(String templateCode, HttpServletResponse response) {
        TemplateEnum templateEnum = TemplateEnum.getByCode(templateCode);
        try(
                InputStream inputStream = ResourceUtil.getResource(templateEnum.getPath()).openStream();
                OutputStream outputStream = response.getOutputStream();
        ) {
            // 根据枚举类型，设置下拉选项
            Workbook workbook = fillDropDownData(templateEnum, inputStream);
            response.setContentType("application/x-download");
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(templateEnum.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
            // 如果 workbook 有值，则代表设置了下拉选项，需要写回 workbook
            if (workbook == null) {
                IOUtils.copy(inputStream, outputStream);
                outputStream.flush();
            } else {
                workbook.write(outputStream);
                outputStream.flush();
                workbook.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Workbook fillDropDownData(TemplateEnum templateEnum, InputStream inputStream) {
        // 如果模板没有填充数据的 json 描述文件，则无需填充数据直接返回
        if (templateEnum.getDropDownDataFillJsonPath() == null) {
            return null;
        }

        // 创建工作簿
        Workbook workbook = WorkbookUtil.createBook(inputStream);

        // 读取 json 描述文件
        String dropDownDataJsonStr = ResourceUtil.readUtf8Str(templateEnum.getDropDownDataFillJsonPath());
        JSONArray jsonArray = JSONUtil.parseArray(dropDownDataJsonStr);
        List<DropDownDataFillDTO> dropDownDataFillList = JSONUtil.toList(jsonArray, DropDownDataFillDTO.class);

        // 循环遍历设置下拉数据
        for (DropDownDataFillDTO dropDownDataFill : dropDownDataFillList) {
            for (DropDownDataFillDTO.DataDescriptions dataDescriptions : dropDownDataFill.getDataDescriptions()) {
                // 数据字典填充
                if (dataDescriptions.getDataType() == DropDownDataFillDTO.DataType.dict) {
                    List<String> dictLabel = dictService.getByKey(dataDescriptions.getDataKey());
                    dataDescriptions.setDataList(dictLabel);
                }
                // IDataService 填充
                if (dataDescriptions.getDataType() == DropDownDataFillDTO.DataType.IDataFillService) {
                    IDataFillService dataFillService = (IDataFillService)applicationContext.getBean(dataDescriptions.getDataKey());
                    List<String> dataList = dataFillService.getFillData();
                    dataDescriptions.setDataList(dataList);
                }
            }
        }

        // 将下拉数据存储到隐藏的 sheet 中
        for (DropDownDataFillDTO dropDownDataFillDTO : dropDownDataFillList) {
            String hiddenSheetName = "hidden_" + dropDownDataFillDTO.getSheetIndex();
            Sheet hiddenSheet = workbook.createSheet(hiddenSheetName);
            workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true);
            List<DropDownDataFillDTO.DataDescriptions> dataDescriptionsList = dropDownDataFillDTO.getDataDescriptions();
            for (int column = 0; column < dataDescriptionsList.size(); column++) {
                List<String> dataList = dataDescriptionsList.get(column).getDataList();
                for (int row = 0; row < dataList.size(); row++) {
                    Row hiddenSheetRow = hiddenSheet.getRow(row);
                    if (hiddenSheetRow == null) {
                        hiddenSheetRow = hiddenSheet.createRow(row);
                    }
                    Cell cell = hiddenSheetRow.createCell(column);
                    cell.setCellValue(dataList.get(row));
                }
                // 没有数据时，不填充
                if (dataList.size() == 0) {
                    continue;
                }
                // 存储 Name 用于设置下拉数据
                Name namedCell = workbook.createName();
                namedCell.setNameName(hiddenSheetName + "_" + column);
                String columnLetter = CellReference.convertNumToColString(column);
                namedCell.setRefersToFormula(String.format("%s!$%s$1:$%s$%s", hiddenSheetName, columnLetter, columnLetter, dataList.size()));
                dataDescriptionsList.get(column).setNamedCell(namedCell);
            }
        }

        // 填充下拉选项
        for (DropDownDataFillDTO dropDownDataFill : dropDownDataFillList) {
            int sheetIndex = dropDownDataFill.getSheetIndex();
            Sheet sheet = workbook.getSheetAt(sheetIndex);
            for (DropDownDataFillDTO.DataDescriptions dataDescription : dropDownDataFill.getDataDescriptions()) {
                DataValidationHelper validationHelper = sheet.getDataValidationHelper();
                if (dataDescription.getNamedCell() == null) {
                    continue;
                }
                // 数据有效性对象
                DataValidationConstraint constraint = validationHelper.createFormulaListConstraint(dataDescription.getNamedCell().getNameName());
                // 四个参数：要添加下拉框的首行、末行、首列、末列
                CellRangeAddressList addressList = new CellRangeAddressList(dataDescription.getStartRowIndex(), dataDescription.getEndRowIndex(),
                        dataDescription.getStartColumnIndex(), dataDescription.getEndColumnIndex());
                DataValidation validation = validationHelper.createValidation(constraint, addressList);
                sheet.addValidationData(validation);
            }
        }
        return workbook;
    }
}
